using System;
using Castle.ActiveRecord;
using Castle.Components.Validator;
using NHibernate.Criterion;
using System.Collections.Generic;

namespace DecisionMaking.Domain
{
	[ActiveRecord]
	public class Environment : ActiveRecordValidationBase<Environment>
	{
		public Environment ()
		{
			Settings = new EnvironmentSettings();
		}
		
	    [PrimaryKey(PrimaryKeyType.Native)]
	    public int Id {set; get;}	
		
		[BelongsTo(NotNull = true, UniqueKey = "uix_environment_name")]
		public Account Account {set; get;}
		
		[Property(NotNull = true, UniqueKey = "uix_environment_name"), ValidateLength(2, 50)]
		public string Name {set; get;}		
		
		[Property(ColumnType = "StringClob")]
		public string Description {set; get;}

		[Property(NotNull = true), ValidateLength(2, 50)]
		public string IndependentVariableName {set; get;}		
		
		[Property(NotNull = true)]
		public Status Status {set; get;}
		
		[Nested]
		public EnvironmentSettings Settings {set; get;}
		
		/// <summary>
		/// Returns a list of environments owned by the specified account 
		/// </summary>
		/// <param name="accountId">
		/// A <see cref="System.Int32"/>
		/// </param>
		/// <returns>
		/// A <see cref="IList<Environment>"/>
		/// </returns>
		public static IList<Environment> FindByAccountId(int accountId)
		{
			return FindAll(
			    DetachedCriteria.For(typeof(Environment))
			    .CreateCriteria("Account")
			    .Add(Restrictions.IdEq(accountId))        
			);               	
		}

        /// <summary>
        /// Returns a list of environments that are either publicly visible or owned by the specified account
        /// </summary>
        /// <param name="accountId"></param>
        /// <returns></returns>
        public static IList<Environment> FindByAccountIdOrPublic(int accountId)
        {
            var criteria = DetachedCriteria.For(typeof(Environment));
            criteria.CreateCriteria("Account", "account");

            // is public or account id is specified account id
            criteria.Add(Restrictions.Disjunction()
                .Add(Restrictions.Eq("Settings.IsPublic", true))
                .Add(Restrictions.Eq("account.Id", accountId))
            );

            return FindAll(criteria);
        }

        /// <summary>
        /// Returns true if this environment has cue attributes defined
        /// </summary>
        /// <returns></returns>
        public bool HasCueAttributes()
        {
            return CountRelation(typeof(CueAttribute)) > 0;
        }

        /// <summary>
        /// Returns true if this environment has cues defined
        /// </summary>
        /// <returns></returns>
        public bool HasCues()
        {
            return CountRelation(typeof(Cue)) > 0;
        }

        /// <summary>
        /// Returns true if this environment has candidates defined
        /// </summary>
        /// <returns></returns>
        public bool HasCandidates()
        {
            return CountRelation(typeof(Candidate)) > 0;
        }

        /// <summary>
        /// Returns true if this environment has agents defined
        /// </summary>
        /// <returns></returns>
        public bool HasAgents()
        {
            return CountRelation(typeof(Agent)) > 0;
        }

        private int CountRelation(Type type)
        {
            var crit = DetachedCriteria.For(type);
            crit.CreateCriteria("Environment").Add(Restrictions.IdEq(Id));

            return Count(crit);
        }
		
		public override bool Equals (object obj)
		{
			if (obj == null)
				return false;
			if (ReferenceEquals (this, obj))
				return true;
			if (obj.GetType () != typeof(Environment))
				return false;
			DecisionMaking.Domain.Environment other = (DecisionMaking.Domain.Environment)obj;
			return Id == other.Id;
		}


		public override int GetHashCode ()
		{
			unchecked {
				return Id.GetHashCode ();
			}
		}

	}
}

